using System;
using System.Collections.Generic;
using System.Linq;
using RomanJendrusz.Amazon.ETL.Domain;
using RomanJendrusz.Amazon.ETL.Infrastructure.Loging.Core;
using RomanJendrusz.Amazon.ETL.Repositories;
using RomanJendrusz.Amazon.ETL.Services;

namespace RomanJendrusz.Amazon.ETL.Tasks
{
    public class BookTask
    {
        private readonly IBookService bookService;
        private readonly IUnitOfWork unitOfWork;
        private readonly IMarketPlaceService marketPlaceService;
        private static List<Book> booksCheckedForSimiliarity = new List<Book>();
        private static List<Book> booksBrowseNodesRetrieved = new List<Book>();

        public BookTask(IBookService bookService, IUnitOfWork unitOfWork, IMarketPlaceService marketPlaceService)
        {
            this.bookService = bookService;
            this.unitOfWork = unitOfWork;
            this.marketPlaceService = marketPlaceService;
        }

        public Book RetrieveBookBy(string ISBN)
        {
            return RetrieveBookBy(ISBN, false);
        }

        public Book RetrieveBookBy(string identifier, bool isAsin)
        {
            LogGateway.LogFor(GetType()).Warn(string.Format("Retrieving informations for book with asin {0}", identifier));
            Book persistedBook;
            IBookRepository bookRepository = unitOfWork.BookRepository;
            if (isAsin)
            {
                persistedBook = bookRepository.FindBookByAsin(identifier, AmazonConstants.OlderEntityDate);
            }
            else
            {
                persistedBook = bookRepository.FindBookByISBN(identifier, AmazonConstants.OlderEntityDate);
            }
            if (persistedBook != null)
            {
                LogGateway.LogFor(GetType()).Warn("The book is allready persisted");
                return persistedBook;
            }
            Book book;
            if(isAsin)
            {
                book = bookService.GetBookDetailsByAsin(identifier);
            }
            else
            {
                book = bookService.GetBookDetailsByIsbn(identifier);
            }
            if(book == null)
            {
                AmazonCounters.ItemsThatAreNotBooks++;
                return null;
            }
            AmazonCounters.BooksRetrieved++;
            book = bookRepository.AttachIfAllreadyExists(book);
            bookRepository.Add(book);
            LogGateway.LogFor(GetType()).Warn(string.Format("Adding book with asin {0} and title {1}", book.Asin, book.Title));
            unitOfWork.SubmitChanges();
            return book;
        }

        public IList<SimiliarBook> RetrieveSimiliarBooksFor(Book book)
        {
            AmazonCounters.BooksCheckedForSimiliarity++;
            if (booksCheckedForSimiliarity.Contains(book))
            {
                LogGateway.LogFor(GetType()).Warn(string.Format("The book with asin: {0} and title '{1}' was allready looked up for similiar books", book.Asin, book.Title));
                return null;    
            }
            ICollection<Book> similiarBooks = bookService.GetSimiliarBooksFor(book);
            foreach (Book similiarBook in similiarBooks)
            {
                Book simBook = RetrieveBookBy(similiarBook.Asin, true);
                if (simBook != null)
                {
                    if (unitOfWork.BookRepository.FindSimiliarity(book, simBook) == null)
                    {
                        var similiarity = new SimiliarBook {Book = book, BooksSimiliarTo = simBook};
                        book.SimiliarBooks.Add(similiarity);
                    }
                    unitOfWork.SubmitChanges();
                }
            }
            booksCheckedForSimiliarity.Add(book);
            return book.SimiliarBooks.ToList();
        }

        public IList<BrowseNode> RetrieveBrowseNodesFor(Book book)
        {
            if(booksBrowseNodesRetrieved.Contains(book))
            {
                LogGateway.LogFor(GetType()).Warn(string.Format("Browse nodes for book with asin {0} and title {1} were allready retrieved", book.Asin, book.Title));
                return null;
            }
            if (book.Updated > AmazonConstants.OlderEntityDate)
            {
                LogGateway.LogFor(GetType()).Warn(string.Format("Browse nodes for book {0} with asin {1} were retrieved earlier then the update entity date", book.Title, book.Asin));
                return null;
            }
            LogGateway.LogFor(GetType()).Warn(string.Format("Retrieving browse nodes for book with asin {0} and title {1}", book.Asin, book.Title));
            IList<BrowseNode> nodes = bookService.GetBrowseNodesFor(book);
            foreach(var retrievedNode in nodes)
            {
                IBrowseNodeRepository repository = unitOfWork.BrowseNodeRepository;
                var node = repository.AttachIfAllreadyExists(retrievedNode);
                repository.Add(node);
            }
            unitOfWork.SubmitChanges();
            booksBrowseNodesRetrieved.Add(book);
            return nodes;
        }
    }
}